﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DevOnServer
{
    public class CPacketHandler
    {
        public CPacketHandler(CGameServer server)
        {
            m_server = server;
        }

        public bool handle(CGamePlayer player)
        {
            CPacket packet = player.Client.Incomming;

            if (packet.readByte() != 0x5e)
                return false;

            packet.move(4);
            if (packet.readInt() > packet.Lenght - 13)
                return false;

            packet.move(8);

            uint cmd = (uint)packet.readInt();
            switch (cmd)
            {
                case 0xff00:
                    return _authPlayer(player);

                case 0xffffff00:
                    return _mouseControl(player);

                case 0xfffff000:
                    return _mapSecurity(player);

                case 0xff0000:
                    return _chat(player);

                case 0xffffff08:
                    return _correctMoverHeight(player);

                case 0xffffff05:
                case 0xffffff02:
                case 0xffffff01:
                    return _keyboardControl(player);

                case 0xffffff72:
                    return _followedArrived(player);

                case 0xffffff07:
                    return _objCliqued(player);

                case 0xff0010:
                case 0xff0011:
                case 0xff0012:
                    return _attack(player);

                case 0xff0023:
                    return _targetChange(player);

                case 0xff0006:
                    return _invMoveItem(player);

                case 0xff00c1:
                    return _revival(player);

                default:
                    CConsole.WriteLine("Unknown packet command : {0:x}", cmd);
                    break;
            }

            return !packet.End;
        }

        private bool _authPlayer(CGamePlayer player)
        {
            CPacket packet = player.Client.Incomming;

            packet.move(29); // pas utilisé

            string charname = packet.readString();
            string username = packet.readString();
            string password = packet.readString();

            CAccount account = m_server.Database.getAccount(username);

            if (account == null
                || account.Password != password
                || account.AccessLevel == 0
                || account.BanTime >= CTime.seconds())
                return false;

            player.Account = account;

            if (!m_server.Database.loadCharacter(player, charname))
                return false;

            if (m_server.Worlds.ContainsKey(player.Character.WorldID))
                m_server.Worlds[player.Character.WorldID].addPlayer(player);

            return false;
        }

        private bool _mouseControl(CGamePlayer player)
        {
            if (player.Object == null)
                return false;

            CPacket packet = player.Client.Incomming;

            packet.move(3);
            player.Object.walk(packet.readPosition());
            packet.move(1);

            return !packet.End;
        }

        private bool _mapSecurity(CGamePlayer player)
        {
            CPacket packet = player.Client.Incomming;

            packet.move(packet.readInt());
            packet.move(packet.readInt());

            return !packet.End;
        }

        private bool _chat(CGamePlayer player)
        {
            if (player.Object == null)
                return false;

            CPacket packet = player.Client.Incomming;

            m_server.ChatHandler.chat(player, packet.readString());

            return !packet.End;
        }

        private bool _correctMoverHeight(CGamePlayer player)
        {
            CPacket packet = player.Client.Incomming;

            packet.readInt();

            return !packet.End;
        }

        private bool _keyboardControl(CGamePlayer player)
        {
            if (player.Object == null)
                return false;

            CPacket packet = player.Client.Incomming;

            CVec3Df startPos = packet.readPosition();
            CVec3Df rotation = packet.readPosition();
            packet.readFloat();
            packet.readInt();
            packet.readInt();
            packet.readInt();
            packet.readInt();
            packet.readLong();
            packet.readLong();

            // à faire

            return !packet.End;
        }

        private bool _followedArrived(CGamePlayer player)
        {
            CPacket packet = player.Client.Incomming;

            packet.readInt(); // mover ID

            return !packet.End;
        }

        private bool _objCliqued(CGamePlayer player)
        {
            if (player.Object == null)
                return false;

            CPacket packet = player.Client.Incomming;

            int targetId = packet.readInt();
            packet.readInt();

            CWorldObject obj = player.Object.World.getObject(targetId);

            if (obj.Type == ObjType.Drop)
                obj.World.removeObject(obj);
            else
                player.Object.follow(obj);

            return !packet.End;
        }

        private bool _attack(CGamePlayer player)
        {
            if (player.Object == null)
                return false;

            CPacket packet = player.Client.Incomming;

            int motion = packet.readInt();
            int targetId = packet.readInt();

            packet.readInt();
            packet.readInt();
            packet.readInt();

            CWorldObject obj = player.Object.World.getObject(targetId);

            if (obj != null && obj.Type == ObjType.Monster)
            {
                player.Object.attack((CMonster)obj, motion);
            }

            return !packet.End;
        }

        private bool _targetChange(CGamePlayer player)
        {
            CPacket packet = player.Client.Incomming;

            packet.readInt(); // mover ID
            packet.readByte(); // action

            return !packet.End;
        }

        private bool _invMoveItem(CGamePlayer player)
        {
            if (player.Object == null)
                return false;

            CPacket packet = player.Client.Incomming;

            packet.readByte();
            byte oldPos = packet.readByte();
            byte newPos = packet.readByte();

            player.Object.Inventory.moveItem(oldPos, newPos);

            return !packet.End;
        }

        private bool _revival(CGamePlayer player)
        {
            if (player.Object == null
                || player.Object.IsAlive)
                return false;

            int rate;
            int level = player.Character.Level;
            if (level == 1)
                rate = 8;
            else if (level == 2)
                rate = 6;
            else if (level <= 5)
                rate = 5;
            else if (level <= 10)
                rate = 4;
            else if (level <= 15)
                rate = 3;
            else
                rate = 3;

            player.Object.HP = (int)(player.Object.HPMax * (float)(rate / 10.0f));

            int val = (int)(player.Object.MPMax * (float)(rate / 10.0f));
            if (player.Object.MP < val)
                player.Object.MP = val;
            val = (int)(player.Object.FPMax * (float)(rate / 10.0f));
            if (player.Object.FP < val)
                player.Object.FP = val;

            int worldId = 1;
            CVec3Df revivalPos = new CVec3Df(6968.0f, 100.0f, 3328.8f);

            if (!m_server.Worlds.ContainsKey(worldId))
                worldId = 1;

            player.Object.World.sendToLocalArea(player.Object, CPacketCreator.revival(player.Object));
            player.Object.teleport(revivalPos, m_server.Worlds[worldId]);

            return !player.Client.Incomming.End;
        }

        private CGameServer m_server;
    }
}
